package com.nineclock.approve.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.nineclock.approve.dto.*;
import com.nineclock.approve.mapper.ApproveDefinitionMapper;
import com.nineclock.approve.pojo.ApproveDefinition;
import com.nineclock.approve.service.ActivitiService;
import com.nineclock.approve.service.ApproveDefinitionService;
import com.nineclock.common.enums.ResponseEnum;
import com.nineclock.common.exception.NcException;
import com.nineclock.common.threadlocal.CurrentUserHolder;
import com.nineclock.common.utils.BeanHelper;
import com.nineclock.common.utils.JsonUtils;
import com.nineclock.common.utils.UUIDUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author 黑马程序员
 * @Company http://www.ithiema.com
 * @Version 1.0
 */
@Service
@Slf4j
public class ApproveDefinitionServiceImpl implements ApproveDefinitionService {

    @Autowired
    ApproveDefinitionMapper approveDefinitionMapper;
    @Autowired
    ActivitiService activitiService;

    @Override
    public List<ApproveGroupDefinitionDto> queryApproveGroupDefinition() {
        List<ApproveGroupDefinitionDto> approveGroupDefinitionDtoList = new ArrayList<>();

        //查询当前企业下所有的审批流程
        LambdaQueryWrapper<ApproveDefinition> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ApproveDefinition::getCompanyId, CurrentUserHolder.get().getCompanyId());
        List<ApproveDefinition> approveDefinitionList = approveDefinitionMapper.selectList(wrapper);
        //对列表数据分组， 根据groupType字段分组
        Map<String, List<ApproveDefinition>> map = approveDefinitionList.stream().collect(Collectors.groupingBy(ApproveDefinition::getGroupType));

        //转换 数据
        for (String key : map.keySet()) {
            ApproveGroupDefinitionDto approveGroupDefinitionDto = new ApproveGroupDefinitionDto();
            List<ApproveDefinition> value = map.get(key);
            approveGroupDefinitionDto.setGroupType(key);
            approveGroupDefinitionDto.setDefinitionList(value);
            approveGroupDefinitionDtoList.add(approveGroupDefinitionDto);
        }

        return approveGroupDefinitionDtoList;
    }

    @Override
    public void saveOrEdit(ApproveDefinitionSaveDto approveDefinitionSaveDto) {
        if(approveDefinitionSaveDto == null || approveDefinitionSaveDto.getBaseData() == null){
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }
        //获取基础数据
        ApproveDefinitionBaseDataDto baseData = approveDefinitionSaveDto.getBaseData();
        String id = baseData.getId();
        //如果id为null，是新增操作
        if(StrUtil.isEmpty(id)){
            //复制 基础信息到 审批流程
            ApproveDefinition definition = BeanHelper.copyProperties(baseData, ApproveDefinition.class);

            //把 list集合转换为 json，存储到definition 中
            List<AllowUserObjDto> allowUserJson = baseData.getAllowUserJson();
            String s = JsonUtils.toString(allowUserJson);
            definition.setAllowUserJson(s);

            List<ApproveDefinitionTableDataDto> tableData = approveDefinitionSaveDto.getTableData();
            definition.setFormJson(JsonUtils.toString(tableData));

            String flowData = approveDefinitionSaveDto.getFlowData();
            JSONArray jsonArray = JSONUtil.parseArray(flowData);
            //给流程数据库中每一个节点扩展一个字段(nodeKey)
            this.expandParamWithNodeKey(jsonArray);
            definition.setFlowJson(JsonUtils.toString(jsonArray));

            //需要将所有的表单信息，记录下来并且拓展参数，fieldKey
            List<ColumnObjDto> columns = expandFieldKey(approveDefinitionSaveDto);
            definition.setColumns(JsonUtils.toString(columns));

            definition.setTableName("flow_"+UUIDUtils.getUUID());
            definition.setCreateTime(new Date());
            definition.setCompanyId(CurrentUserHolder.get().getCompanyId() + "");

            approveDefinitionMapper.insert(definition);
        }
        //如果id不为null，是修改操作
        else{
            ApproveDefinition approveDefinition = approveDefinitionMapper.selectById(id);
            approveDefinition.setGroupType(baseData.getGroupType());
            approveDefinition.setName(baseData.getName());
            approveDefinition.setAllowUserJson(JsonUtils.toString(baseData.getAllowUserJson()));
            approveDefinition.setDescription(baseData.getDescription());
            approveDefinition.setIcon(baseData.getIcon());
            approveDefinition.setOpinionPrompt(baseData.getOpinionPrompt());
            approveDefinition.setOpinionRequired(baseData.getOpinionRequired());
            approveDefinition.setSeq(baseData.getSeq());
            approveDefinition.setUpdateTime(new Date());
            //设置表单数据
            List<ApproveDefinitionTableDataDto> tableData = approveDefinitionSaveDto.getTableData();
            approveDefinition.setFormJson(JsonUtils.toString(tableData));


            String flowData = approveDefinitionSaveDto.getFlowData();
            JSONArray jsonArray = JSONUtil.parseArray(flowData);

            //给流程数据库中每一个节点扩展一个字段(nodeKey)
            this.expandParamWithNodeKey(jsonArray);
            approveDefinition.setFlowJson(JsonUtils.toString(jsonArray));

            //将表单信息记录，并拓展参数  fieldKey

            List<ColumnObjDto> columnObjDtos = expandFieldKey(approveDefinitionSaveDto);
            approveDefinition.setColumns(JsonUtils.toString(columnObjDtos));

            //持久化数据库
            approveDefinitionMapper.updateById(approveDefinition);
            //删除审批流程部署到activiti中的数据
            // 动态构造bpmn，部署到 activiti表中
            activitiService.deleteProcessFromActiviti(approveDefinition);

            // 动态构造bpmn，部署到 activiti表中
            activitiService.deployProcessToActiviti(approveDefinition);
        }
    }

    @Override
    public ApproveDefinitionResultDto queryById(String id) {
        if (id == null){
            throw new NcException(ResponseEnum.MESSAGE_PARAMS_LOST);
        }
        ApproveDefinitionResultDto approveDefinitionResultDto =new ApproveDefinitionResultDto();
        //获取审批流程对象
        ApproveDefinition approveDefinition = approveDefinitionMapper.selectById(id);
        if(approveDefinition == null){
            throw new NcException(ResponseEnum.MESSAGE_PARAMS_LOST);
        }
        //将审批流程对象转换成为返回值类型的对象

        ApproveDefinitionBaseDataDto baseDataDto = BeanHelper.copyProperties(approveDefinition, ApproveDefinitionBaseDataDto.class);

        //设置谁可以发起审核
        String allowUserJson = approveDefinition.getAllowUserJson();
        //approveDefinition中的 AllowUserJson 是String 类型的，但是baseDataDto中的AllowUserJson是list
        //用jsonutils 转换
        baseDataDto.setAllowUserJson(JsonUtils.toList(allowUserJson,AllowUserObjDto.class));

        //获取表单中的json数据
        String formJson = approveDefinition.getFormJson();

        List<ApproveDefinitionTableDataResultDto> approveDefinitionTableDataResultDtos = JsonUtils.toList(formJson, ApproveDefinitionTableDataResultDto.class);

        String flowJson = approveDefinition.getFlowJson();

        //为什么可以用链式编程完成赋值？
        //在实体类中  加了一个注解：@Accessors(chain = true)   表示可以使用链式赋值
        // 因为在class文件中，set方法的返回值是this  这个对象
        approveDefinitionResultDto
                .setBaseData(baseDataDto)
                .setTableData(approveDefinitionTableDataResultDtos)
                .setFlowData(flowJson);

        return approveDefinitionResultDto;
    }

    /**
     * 扩充参数 : fieldKey
     * @param approveDefinitionDto
     * @return
     */
    private List<ColumnObjDto> expandFieldKey(ApproveDefinitionSaveDto approveDefinitionDto) {
        List<ColumnObjDto> columns = new ArrayList<>();

        for (ApproveDefinitionTableDataDto tableData : approveDefinitionDto.getTableData()) {
            if(StrUtil.isEmpty(tableData.getFieldKey())){
                tableData.setFieldKey(UUIDUtils.getUUID());
            }

            columns.add(new ColumnObjDto(tableData.getFieldKey(), tableData.getLab(), tableData.getTitle(), "1"));
        }
        return columns;
    }

    private void expandParamWithNodeKey(JSONArray jsonArray) {
        for(int i = 0; i < jsonArray.size(); i++){
            JSONObject jsonNode = (JSONObject) jsonArray.get(i);

            String nodeKey = jsonNode.getStr("nodeKey");
            if(StrUtil.isEmpty(nodeKey)){
                jsonNode.put("nodeKey", UUIDUtils.getUUID());
            }

            //处理网关节点的内部节点 nodeKey
            String type = jsonNode.getStr("type");
            if("condition".equals(type)){

                JSONArray batchArray = (JSONArray) jsonNode.get("node");
                if(batchArray!=null && batchArray.size()>0){

                    for (int j = 0; j < batchArray.size(); j++) {
                        JSONArray innerArray = (JSONArray) batchArray.get(j);

                        if(innerArray!=null && innerArray.size()>0){
                            for (int k = 0; k < innerArray.size(); k++) {
                                JSONObject node = (JSONObject) innerArray.get(k);
                                if(!node.containsKey("nodeKey")){
                                    node.put("nodeKey", UUIDUtils.getUUID());
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
